package com.iims.flowable.factory;

import com.iims.common.core.domain.entity.SysUser;
import com.iims.common.utils.StringUtils;
import com.iims.common.utils.uuid.IdUtils;
import com.iims.flowable.common.constant.FlowableConstant;
import com.iims.flowable.common.enums.CommentTypeEnum;
import com.iims.flowable.flow.CommonUtil;
import com.iims.flowable.flow.ObjectUtils;
import com.iims.flowable.flow.domain.FlowTaskForm;
import com.iims.flowable.flow.vo.CommentResponse;
import com.iims.flowable.flow.vo.HistoricProcessInstanceResponse;
import com.iims.flowable.flow.vo.ModelResponse;
import com.iims.flowable.flow.vo.ProcessInstanceDetailResponse;
import com.iims.flowable.flow.vo.request.SubmitTaskFormVo;
import com.iims.flowable.flow.vo.resp.*;
import org.apache.commons.compress.utils.Lists;
import org.flowable.engine.IdentityService;
import org.flowable.engine.history.HistoricProcessInstance;
import org.flowable.engine.repository.Deployment;
import org.flowable.engine.repository.Model;
import org.flowable.engine.repository.ProcessDefinition;
import org.flowable.engine.runtime.ProcessInstance;
import org.flowable.engine.task.Comment;
import org.flowable.task.api.Task;
import org.flowable.task.api.TaskInfo;
import org.flowable.task.api.history.HistoricTaskInstance;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.util.ArrayList;
import java.util.List;

/**
 * @author fanpei
 * @date 2020年3月24日
 */
@Component
public class FlowResponseFactory extends BaseFlowResource {


    @Autowired
    public FlowResponseFactory(IdentityService identityService) {
        this.identityService = identityService;
    }


    public List<FlowMyProcessInstanceDto> flowTaskMyStartDtoList(List<HistoricProcessInstance> taskList) {
        List<FlowMyProcessInstanceDto> flowList = new ArrayList<>();
        taskList.stream().forEach(hisIns -> {
            FlowMyProcessInstanceDto myct = new FlowMyProcessInstanceDto();
            myct.copyHistoricProcessInstance(hisIns);
            flowList.add(myct);
        });
        return flowList;
    }

    public List<FlowProcDefDto> flowProcDefDtoList(List<ProcessDefinition> list) {
        List<FlowProcDefDto> dataList = new ArrayList<>();
        for (ProcessDefinition procDef : list) {
            String deploymentId = procDef.getDeploymentId();
            FlowProcDefDto reProcDef = new FlowProcDefDto();
            if (procDef.hasStartFormKey()) {
                String startFormKey = formService.getStartFormKey(procDef.getId());
                reProcDef.copyProcessDefinitionList(procDef, startFormKey);
            } else {
                reProcDef.copyProcessDefinitionList(procDef, null);
            }
            Deployment deployment = repositoryService.createDeploymentQuery().deploymentId(deploymentId).singleResult();
            reProcDef.setDeploymentTime(deployment.getDeploymentTime()); // 流程定义时间
            dataList.add(reProcDef);
        }
        return dataList;
    }

    public List<FlowHasDoTaskDto> flowDoneTaskDtoList(List<HistoricTaskInstance> taskList) {
        List<FlowHasDoTaskDto> donList = Lists.newArrayList();
        taskList.stream().forEach(ht -> {
            FlowHasDoTaskDto ft = new FlowHasDoTaskDto();
            ft.copyHistoricTaskInstance(ht);
            initiFlowTaskDtoByProcessDefId(ht.getProcessDefinitionId(), ht.getProcessInstanceId(), ft);
            donList.add(ft);
        });
        return donList;
    }

    public List<FlowHasDoTaskDto> flowToDoTaskDtoList(List<Task> taskList) {
        List<FlowHasDoTaskDto> toDoList = new ArrayList<>();
        taskList.stream().forEach(task -> {
            FlowHasDoTaskDto ft = new FlowHasDoTaskDto();
            ft.copyToDoTask(task);
            initiFlowTaskDtoByProcessDefId(task.getProcessDefinitionId(), task.getProcessInstanceId(), ft);
            toDoList.add(ft);
        });
        return toDoList;
    }

    /**
     * 初始化任务信息
     *
     * @param processDefinitionId
     * @return
     */
    private void initiFlowTaskDtoByProcessDefId(String processDefinitionId, String processInstanceId, FlowHasDoTaskDto ft) {
        // 2.流程定义信息
        ProcessDefinition pd = repositoryService.createProcessDefinitionQuery()
                .processDefinitionId(processDefinitionId)
                .singleResult();
        ft.setProcessDefinitionName(pd.getName());

        // 3.流程发起人信息
        HistoricProcessInstance historicProcessInstance = historyService.createHistoricProcessInstanceQuery()
                .processInstanceId(processInstanceId)
                .singleResult();
        SysUser startUser = sysUserService.selectUserByCode(historicProcessInstance.getStartUserId());
        ft.setStartUserCode(startUser.getUser_code());
        ft.setStartUserName(startUser.getNickName());
        ft.setStartDeptName(startUser.getDept().getDeptName());
    }

    @Deprecated
    public ProcessInstanceDetailResponse createProcessInstanceDetailResponse(HistoricProcessInstance hisProcessInstance, ProcessInstance processInstance) {
        ProcessInstanceDetailResponse result = new ProcessInstanceDetailResponse();
        HistoricProcessInstanceResponse.createHistoricProcessInstanceResponse(hisProcessInstance);
        result.setStartUserName(getUserName(hisProcessInstance.getStartUserId()));
        result.setDeleteReason(hisProcessInstance.getDeleteReason());
        if (processInstance != null) {
            result.setSuspended(processInstance.isSuspended());
        }
        return result;
    }

    public ProcessInsDetailResponse createProcessInsDetail(HistoricProcessInstance hisProcessInstance, ProcessInstance processInstance) {
        ProcessInsDetailResponse result = new ProcessInsDetailResponse();
        result.setProcessInstanceId(hisProcessInstance.getId());
        result.setName(hisProcessInstance.getName());
        result.setBusinessKey(hisProcessInstance.getBusinessKey());
        result.setCreateTime(hisProcessInstance.getStartTime());
        result.setEndTime(hisProcessInstance.getEndTime());
        result.setDuration(FlowFiledUtils.getDate(hisProcessInstance.getDurationInMillis()));
        result.setSuperProcessInstanceId(hisProcessInstance.getSuperProcessInstanceId());
        //result.setTenantId(processInstance.getTenantId());
        result.setStartUserName(getUserName(hisProcessInstance.getStartUserId()));
        result.setDeleteReason(hisProcessInstance.getDeleteReason());

        result.setProcessDefinitionId(processInstance.getProcessDefinitionId());
        result.setProcessDefinitionKey(processInstance.getProcessDefinitionKey());
        result.setProcessDefinitionName(processInstance.getProcessDefinitionName());
        result.setVersion(processInstance.getProcessDefinitionVersion());
        if (processInstance != null) {
            result.setSuspended(processInstance.isSuspended());
        }
        return result;
    }

    public List<ModelResponse> createModelResponseList(List<Model> models) {
        List<ModelResponse> responseList = new ArrayList<>();
        for (Model instance : models) {
            responseList.add(createModelResponse(instance));
        }
        return responseList;
    }

    public ModelResponse createModelResponse(Model model) {
        ModelResponse response = new ModelResponse();
        response.setCategory(model.getCategory());
        response.setCreateTime(model.getCreateTime());
        response.setId(model.getId());
        response.setKey(model.getKey());
        response.setLastUpdateTime(model.getLastUpdateTime());
        response.setDescription(model.getMetaInfo());
        response.setName(model.getName());
        response.setVersion(model.getVersion());
        if (model.getDeploymentId() != null) {
            response.setDeployed(true);
        } else {
            response.setDeployed(false);
        }
        response.setTenantId(model.getTenantId());
        return response;
    }

    public List<CommentResponse> createCommentResponseList(List<Comment> comments) {
        List<CommentResponse> responseList = new ArrayList<>();
        for (Comment comment : comments) {
            if (CommonUtil.isNotEmptyAfterTrim(comment.getTaskId())) {
                CommentResponse commentResponse = new CommentResponse();
                commentResponse.setId(comment.getId());
                commentResponse.setUserId(comment.getUserId());
                commentResponse.setUserName(getUserName(comment.getUserId()));
                commentResponse.setUserDept(getUserDept(comment.getUserId()));
                commentResponse.setType(comment.getType());
                commentResponse.setTypeDesc(CommentTypeEnum.getEnumMsgByType(comment.getType()));
                commentResponse.setTime(comment.getTime());
                commentResponse.setProcessInstanceId(comment.getProcessInstanceId());
                commentResponse.setTaskId(comment.getTaskId());

                TaskInfo task = historyService.createHistoricTaskInstanceQuery().taskId(comment.getTaskId()).singleResult();
                commentResponse.setTaskName(task.getName());
                commentResponse.setFullMessage(comment.getFullMessage());
                responseList.add(commentResponse);
            }
        }
        return responseList;
    }

    /**
     * 存储起始表单表单数据
     */
    public void commitTaskForm(String userId, SubmitTaskFormVo taskFormVo, String taskId, String processInstanceId, String processDefinitionId) {
        if (null != taskFormVo) {
            String startFormKey = formService.getStartFormKey(processDefinitionId);
            FlowTaskForm taskForm = new FlowTaskForm();
            taskForm.setProcInstId(processInstanceId);
            taskForm.setProcDefId(processDefinitionId);
            taskForm.setFormDataBack(taskFormVo.getFormDataBack());
            taskForm.setFormDataJson(taskFormVo.getFormDataJson());
            taskForm.setCreateBy(userId);
            if (ObjectUtils.isEmpty(taskId)) {
                taskForm.setTaskId(IdUtils.simpleUUID());
            } else {
                taskForm.setTaskId(taskId);
            }
            if (StringUtils.isEmpty(startFormKey)) {
                taskForm.setFormKey(FlowableConstant.PROCESS_INSTANCE_FORM_DATA);
            } else {
                taskForm.setFormKey(startFormKey);
            }
            cmisTaskFormService.insertUpdateTaskForm(taskForm);
        }
    }
}